from datetime import timedelta, datetime

import pandas as pd
import pytz
from django.db import transaction
from django.http import HttpResponse
from rest_framework.parsers import MultiPartParser, FormParser

# Create your views here.
# 创建增删改查视图 rest api
from .serializers import CourseSelectionSerializer, SelectionInfoSerializer
from CourseSelection.models import *  # 或者显式导入每个模型类
from django.utils.dateparse import parse_datetime
from rest_framework import status
from rest_framework.permissions import BasePermission
from rest_framework.response import Response
from rest_framework.views import APIView
from UserManager.models import User


def get_model_fields_info(model_class):
    fields_info = {'model_name': model_class._meta.verbose_name}

    for field in model_class._meta.get_fields(include_hidden=True):
        # 获取字段的基本信息
        field_name = field.name
        field_type = field.__class__.__name__
        verbose_name = field.verbose_name

        # 获取choices信息，如果有的话
        choices = None
        if hasattr(field, 'choices') and field.choices:
            choices = field.choices
            # 提取每个子数组的第一个元素
            choices = [sublist[0] for sublist in choices]

        # 将信息存入字典
        fields_info[field_name] = {
            'type': field_type,
            'verbose_name': verbose_name,
            'choices': choices,
        }

    return fields_info


# 获取所有模型类
course_manager_config = apps.get_app_config('CourseSelection')
model_classes = course_manager_config.get_models()
# 构建模型信息字典

model_info_dict = {model.__name__: get_model_fields_info(model) for model in model_classes}


# 设置权限类
class IsTDAdmin(BasePermission):
    # 判断是否在reviewer组内
    def has_permission(self, request, view):
        if request.user.groups.filter(name='TDAdmin').exists():
            return True
        return False


# 定义一个视图类 增加数据
class CourseSelectionViewSet(APIView):
    queryset = CourseSelection.objects.all()
    serializer_class = CourseSelectionSerializer
    permission_classes = [IsTDAdmin]

    def post(self, request):
        serializer = CourseSelectionSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


# 删除
class CourseSelectionViewDelete(APIView):
    queryset = CourseSelection.objects.all()
    serializer_class = CourseSelectionSerializer
    permission_classes = [IsTDAdmin]

    def post(self, request):
        # 以id获取模型实例
        try:
            course = CourseSelection.objects.get(id=request.data['id'])
            course.delete()
            return Response({'success': 'deleted successfully'}, status=status.HTTP_201_CREATED)
        except Exception as e:
            return Response({'error': str(e)}, status=400)


# 修改
class CourseSelectionViewUpdate(APIView):
    queryset = CourseSelection.objects.all()
    serializer_class = CourseSelectionSerializer
    permission_classes = [IsTDAdmin]

    def post(self, request):
        # 以id获取模型实例
        try:
            course = CourseSelection.objects.get(id=request.data['id'])
            serializer = CourseSelectionSerializer(course, data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data, status=status.HTTP_201_CREATED)
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            return Response({'error': str(e)}, status=400)


# 查询
class CourseSelectionViewGet(APIView):
    queryset = CourseSelection.objects.all()
    serializer_class = CourseSelectionSerializer

    def post(self, request):
        # 获取模型所有的实例
        try:
            courses = CourseSelection.objects.all()
            courses = self.filter_reports_by_year_semester(request, courses)
            serializer = CourseSelectionSerializer(courses, many=True)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        except Exception as e:
            return Response({'error': str(e)}, status=400)

    def filter_reports_by_year_semester(self, request, course_selections):
        year = request.data.get('year')
        semester = request.data.get('semester')
        if not year and not semester:
            return course_selections
        elif not semester:
            return course_selections.filter(year=year)
        elif not year:
            return course_selections.filter(semester=semester)
        else:
            return course_selections.filter(year=year, semester=semester)


# 查询可选的课程
class CourseSelectionViewGetAvailable(APIView):
    queryset = CourseSelection.objects.all()
    serializer_class = CourseSelectionSerializer

    def post(self, request):
        # 获取模型所有的实例
        try:
            courses = CourseSelection.objects.all()
            courses = self.filter_reports_by_year_semester(request, courses)
            courses = self.filter_reports_by_is_open(request, courses)
            serializer = CourseSelectionSerializer(courses, many=True)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        except Exception as e:
            return Response({'error': str(e)}, status=400)

    def filter_reports_by_year_semester(self, request, course_selections):
        year = request.data.get('year')
        semester = request.data.get('semester')
        if not year and not semester:
            return course_selections
        elif not semester:
            return course_selections.filter(year=year)
        elif not year:
            return course_selections.filter(semester=semester)
        else:
            return course_selections.filter(year=year, semester=semester)

    def filter_reports_by_is_open(self, request, course_selections):
        is_open = True
        return course_selections.filter(is_open=is_open)



# 批量增加，通过上传的excel文件直接批量增加
class CourseSelectionViewBatchAdd(APIView):
    parser_classes = [MultiPartParser, FormParser]  # 添加支持multipart/form-data的解析器
    def post(self, request):
        try:
            # 使用事务保证数据一致性
            with transaction.atomic():
                # 获取客户端上传的excel文件 xlsx格式
                excel_file = request.FILES.get('excel_file')
                if not excel_file:
                    return Response({"error": "No file uploaded."}, status=status.HTTP_400_BAD_REQUEST)

                # 利用pandas加载
                df = pd.read_excel(excel_file)

                # 遍历DataFrame，创建并保存每个CourseSelection实例
                for index, row in df.iterrows():
                    # 确保数据清洗和验证，例如检查必填字段
                    # 这里简化处理，实际应用中需要更详细的错误处理逻辑
                    course_selection_data = row.to_dict()  # 将每一行转换为字典

                    # 创建模型实例
                    course_selection = CourseSelection(**course_selection_data)

                    # 验证模型实例（这会触发模型的clean方法）
                    try:
                        course_selection.full_clean()
                    except ValidationError as e:
                        # 如果数据不合法，记录错误或直接返回错误信息
                        raise ValueError(str(e))  # 改为抛出异常以触发事务回滚

                    # 保存到数据库
                    course_selection.save()

                # 如果所有数据都成功处理，事务会在此自动提交
                return Response({"message": "Data imported successfully."}, status=status.HTTP_201_CREATED)

        except ValueError as ve:  # 捕获特定的验证错误
            return Response({"error": str(ve) + "  请你检查数据是否合规，year为年 只能是类似 2023-2024、2024-2025"},
                            status=status.HTTP_400_BAD_REQUEST)
        except Exception as e:  # 捕获其他所有异常
            return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


# 开启选课
"""
Max_course_hour={

}
"""
Max_course_hour = {
    '助教': 240,
    '讲师': 190,
    '副教授': 190,
    '教授': 160,
}


class CourseSelectionViewStart(APIView):
    def post(self, request):
        try:
            # 获取清空SelectionInfo
            SelectionInfo.objects.all().delete()
            # 重置id

            results = []
            users = User.objects.all()


            for user in users:
                result = {'account': user.username, 'name': user.name, "score": 0}
                userscores = UserScore.objects.filter(account=user.username)
                userscores = self.filter_reports_by_time(request, userscores)
                for userscore in userscores:
                    result['score'] += userscore.score
                results.append(result)

            # 根据每个元素的"score"由大到小对元素进行排序
            results.sort(key=lambda x: x['score'], reverse=True)
            # 从request中获取选课的总体时间段
            choose_start_time = parse_datetime(request.data.get('choose_start_time'))
            choose_end_time = parse_datetime(request.data.get('choose_end_time'))
            # 在时间段内每天的的9:00--21:00是选课时间，根据分数排名为每位用户平均分配时间
            start_time = choose_start_time
            for i in range(len(results)):
                # 如果root用户 则跳过
                if results[i]['account'] == 'root':
                    continue
                # 获取当前排名的用户
                user = results[i]
                # 计算总选课时间长度，时间段内每天的的9:00--21:00是选课时间，其它时间不计入时间段长度
                total_time_length = (choose_end_time - choose_start_time).total_seconds() / 3600
                # 计算每个用户的平均时间长度，时间段内每天的的9:00--21:00是选课时间，其它时间不计入时间段长度
                avg_time_length = total_time_length / len(results)
                # 为当前用户分配时间段
                end_time = start_time + timedelta(hours=avg_time_length)

                selectionInfo = {
                    'author_account': user['account'],
                    'author_name': user['name'],
                    'start_time': start_time,
                    'end_time': end_time,
                    'is_finish': False
                }
                start_time = end_time + timedelta(seconds=1)
                # 获取序列化保存去数据库
                serializer = SelectionInfoSerializer(data=selectionInfo)
                if serializer.is_valid():
                    serializer.save()
            return Response({"message": "课程选择已经开启."}, status=status.HTTP_201_CREATED)
        except Exception as e:
            return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def filter_reports_by_time(self, request, userscores):
        start_time = request.data.get('score_start_time')
        end_time = request.data.get('score_end_time')
        if not start_time or not end_time:
            return Response(
                {"error": "请提供 score_start_time 和 score_end_time 参数，因为需要以时间范围来计算用户分数"},
                status=status.HTTP_400_BAD_REQUEST)
            # 将字符串时间转换为 Python datetime 对象
        start_time = parse_datetime(start_time)
        end_time = parse_datetime(end_time)

        # 应用时间范围过滤
        userscores = userscores.filter(created_time__range=(start_time, end_time))

        return userscores


# 下载选课结果，将CourseSelection模型的数据以excel表存储并下载
class CourseSelectionViewDownload(APIView):
    def post(self, request):
        try:
            results = []
            course_selections = CourseSelection.objects.all()
            course_selections = self.filter_reports_by_year_semester(request, course_selections)
            for course_selection in course_selections:
                result = {
                    'year': course_selection.year,
                    'semester': course_selection.semester,
                    'grade': course_selection.grade,
                    'major': course_selection.major,
                    'class_name': course_selection.class_name,
                    'course_name': course_selection.course_name,
                    'course_id': course_selection.course_id,
                    'course_hour': course_selection.course_hour,
                    'teacher_account': course_selection.teacher_account,
                    'teacher_name': course_selection.teacher_name
                }
                results.append(result)
            # 将数据写入Excel文件
            df = pd.DataFrame(results)
            df.to_excel('course_selection.xlsx', index=False)
            return self.send_file('course_selection.xlsx', as_attachment=True)
        except Exception as e:
            return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def send_file(self, filename, as_attachment=False):
        try:
            # 读取文件
            with open(filename, 'rb') as f:
                # 创建响应对象
                response = HttpResponse(f.read(), content_type='application/vnd.openxmlformats-officedocument'
                                                               '.spreadsheetml.sheet')
                # 设置响应头
                response['Content-Disposition'] = f'attachment; filename="{filename}"'
                return response
        except Exception as e:
            return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    # 通过year和semester筛选
    def filter_reports_by_year_semester(self, request, course_selections):
        year = request.data.get('year')
        semester = request.data.get('semester')
        if not year and not semester:
            return course_selections
        elif not semester:
            return course_selections.filter(year=year)
        elif not year:
            return course_selections.filter(semester=semester)
        else:
            return course_selections.filter(year=year, semester=semester)


# 用户选课
class CourseSelectionViewForUser(APIView):
    selectionInfo = None

    def post(self, request):
        try:
            # 首先判断user是否可以选课，如果不可以，则返回错误信息
            # 在SelectionInfo中去找到该用户的选课时间，以及相关ID
            if self.has_permission_choose(request):
                self.choose(request)
            else:
                return Response({"error": "您没有权限选课，请确认你是否在选课时间段内"},
                                status=status.HTTP_403_FORBIDDEN)
        except Exception as e:
            return Response({"error ": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    # 选课权限判断
    def has_permission_choose(self, request):
        # 获取当前用户的选课信息
        self.selectionInfo = SelectionInfo.objects.get(author_account=request.user.username)
        id = self.selectionInfo.id
        if self.selectionInfo.is_finish:
            return Response({"error": "您已经选课完毕，不能再选课"}, status=status.HTTP_400_BAD_REQUEST)
        # 获取当前id的上一个id的selectionInfo
        # 判断previous_selectionInfo = SelectionInfo.objects.get(id=id - 1)是否存在
        if not SelectionInfo.objects.filter(id=id - 1).exists():
            previous_selectionInfo = self.selectionInfo
        else:
            previous_selectionInfo = SelectionInfo.objects.get(id=id - 1)

        start_time = self.selectionInfo.start_time.replace(tzinfo=None)
        end_time = self.selectionInfo.end_time.replace(tzinfo=None)
        # 获取当前时间如果不在时间段内不得选课
        current_time = datetime.now()
        print("current_time:", current_time, "start_time:", start_time, "end_time:", end_time)
        if previous_selectionInfo.is_finish and current_time < end_time:
            # 上一位已经选课结束且没有到达你的选课结束时间，您可以提前选课
            return True
        elif not previous_selectionInfo.is_finish and end_time > current_time > start_time:
            # 上一位没有选课，你可以先选课
            return True
        return False

    def choose(self, request):
            with transaction.atomic():  # 开启事务
                # 解析request的data，获知当前用户要选择CourseSelection的id
                course_selection_ids = request.data.get("course_selection_ids")
                if not course_selection_ids:
                    raise ValueError("请提供 course_selection_ids 参数")  # 更改为抛出具体异常类型

                for course_selection_id in course_selection_ids:
                    course_selection = CourseSelection.objects.get(id=course_selection_id)
                    if (course_selection.teacher_account is None
                            and course_selection.teacher_name is None):
                        course_selection.teacher_account = request.user.username
                        course_selection.teacher_name = request.user.name
                        course_selection.save()
                    else:
                        # 直接抛出异常，不需要包裹Response，因为外层会处理
                        raise ValueError(f"{course_selection_id} 课程选择失败，请检查原因。")

                self.selectionInfo.is_finish = True
                self.selectionInfo.save()

            return Response({"message": "选课成功，你已经无法对此进行任何操作。"}, status=status.HTTP_201_CREATED)


    # 选课规范


# 用户取消选课
class CourseSelectionViewForUserCancel(APIView):
    def post(self, request):
        try:
            # 首先判断user是否可以取消选课，如果不可以，则返回错误信息
            # 在SelectionInfo中去找到该用户的选课时间，以及相关ID
            if self.has_permission_cancel(request):
                self.cancel(request)
        except Exception as e:
            return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    # 取消选课权限判断
    def has_permission_cancel(self, request):
        # 获取当前用户的选课信息
        selectionInfo = SelectionInfo.objects.get(author_account=request.user.username)
        id = selectionInfo.id
        if selectionInfo.is_finish:
            return Response({"error": "您已经选课完毕，不能再取消选课"}, status=status.HTTP_400_BAD_REQUEST)
        elif request.user.username != selectionInfo.author_account:
            return Response({"error": "这不是你选择的课，你无权限取消"}, status=status.HTTP_400_BAD_REQUEST)
        else:
            return True

    def cancel(self, request):
        try:
            # 解析request的data，获知当前用户要选择CourseSelection的id
            course_selection_ids = request.data.get('course_selection_id')
            if not course_selection_ids:
                return Response({"error": "请提供 course_selection_ids 参数"}, status=status.HTTP_400_BAD_REQUEST)
            for course_selection_id in course_selection_ids:
                course_selection = CourseSelection.objects.get(id=course_selection_id)
                if (course_selection.teacher_account is not None
                        or course_selection.teacher_name is not None):
                    course_selection.teacher_account = None
                    course_selection.teacher_name = None
                    course_selection.save()
                    return Response({"success": "取消选课成功"}, status=status.HTTP_200_OK)
        except Exception as e:
            return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


## 查询所有模型字段
class GetModelFieldsView(APIView):
    def post(self, request):
        # 返回model_info_dict
        try:
            fields = model_info_dict

            return Response(fields, status=status.HTTP_200_OK)
        except Exception as e:
            return Response({"message": "获取字段失败：" + str(e)}, status=status.HTTP_400_BAD_REQUEST)
